package cn.doitedu.marketing.engine.querier;

import cn.doitedu.marketing.engine.beans.EventCombinationCondition;
import cn.doitedu.marketing.engine.beans.EventCondition;
import cn.doitedu.marketing.engine.gauges.AvgGauge;
import cn.doitedu.marketing.engine.gauges.CountGauge;
import cn.doitedu.marketing.engine.gauges.QueryGauges;
import lombok.extern.slf4j.Slf4j;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/***
 * @author hunter.d
 * @qq 657270652
 * @wx haitao-duan
 * @date 2021/7/25
 **/
@Slf4j
public class ClickHouseQuerier {
    Connection conn;
    CountGauge countGauge;
    AvgGauge avgRateGauge;

    public ClickHouseQuerier(Connection conn, QueryGauges queryGauges) throws Exception {
        this.conn = conn;
        countGauge = queryGauges.getCkQueryCountGauge();
        avgRateGauge = queryGauges.getCkAvgrateGauge();
    }

    /**
     * 事件序列（可用于单个事件）匹配，返回匹配到的次数
     *
     * @param eventCombinationCondition
     * @param deviceId
     * @param timeRangeStart
     * @param timeRangeEnd
     * @param onlyExists
     * @return
     * @throws Exception
     */
    public int findEventCombinationConditionCount(EventCombinationCondition eventCombinationCondition, String deviceId, long timeRangeStart, long timeRangeEnd, boolean onlyExists) throws Exception {
        String str = getEventCombinationStr(eventCombinationCondition, deviceId, timeRangeStart, timeRangeEnd);
        Pattern r = Pattern.compile(eventCombinationCondition.getMatchPattern());
        Matcher matcher = r.matcher(str);
        int count = 0;
        while (matcher.find()) {
            count++;
            if (onlyExists) return count;
        }
        log.debug("正则表达式为： {} , ck返回的字符串为： {} ,匹配次数为： {}", eventCombinationCondition.getMatchPattern(), str, count);
        return count;
    }

    /**
     * 从ck中获取目标事件，返回事件字符串
     *
     * @param eventCombinationCondition
     * @param deviceId
     * @param timeRangeStart
     * @param timeRangeEnd
     * @return
     * @throws Exception
     */
    public String getEventCombinationStr(EventCombinationCondition eventCombinationCondition, String deviceId, long timeRangeStart, long timeRangeEnd) throws Exception {

        List<String> evIds = getStrings(eventCombinationCondition);

        PreparedStatement pst = conn.prepareStatement(eventCombinationCondition.getQuerySql());
        pst.setString(1, deviceId);
        pst.setLong(2, timeRangeStart);
        pst.setLong(3, timeRangeEnd);

        long s = System.currentTimeMillis();
        ResultSet resultSet = pst.executeQuery();
        StringBuilder sb = new StringBuilder();
        while (resultSet.next()) {
            String ckEStr = resultSet.getString(1);
            sb.append((evIds.indexOf(ckEStr) + 1) + "");
        }
        long e = System.currentTimeMillis();

        countGauge.inc();
        avgRateGauge.inc(e-s);

        return sb.toString();
    }

    private List<String> getStrings(EventCombinationCondition eventCombinationCondition) {
        List<EventCondition> eventParamGroup = eventCombinationCondition.getEventConditionList();
        List<String> evIds = eventParamGroup.stream().map(e -> e.getEventId()).collect(Collectors.toList());
        return evIds;
    }
}
